﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Krile.Cores.KeyAssignElems;

namespace Krile.Forms.ConfigForm.Children
{
    public partial class KeyAssign : Krilib.Control.ConfigPage
    {
        public KeyAssign()
        {
            InitializeComponent();
        }

        KeyAssignCallbackCandidate[] candidates = null;
        Dictionary<Keys, List<KeyAssignMethodData>> kadatas = new Dictionary<Keys, List<KeyAssignMethodData>>();
        private void KeyAssign_Load(object sender, EventArgs e)
        {
            candidates = Core.KeyAssign.GetCandidatesArray();
            foreach (var i in candidates)
            {
                candidateList.Items.Add(i.Description);
            }
            if (candidateList.Items.Count == 0)
                throw new KrileFatalException("Internal data might been corrupted. You have to re-install Krile.");
            else
                candidateList.SelectedIndex = 0;
            if (Core.Config.KeyAssign.KeyAssignData != null)
            {
                foreach (var kid in Core.KeyAssign.AssignDataArray)
                {
                    if (kid.InvokeMethodDatas == null)
                        kadatas.Add(kid.LinkedKeys, new List<KeyAssignMethodData>());
                    else
                        kadatas.Add(kid.LinkedKeys, new List<KeyAssignMethodData>(kid.InvokeMethodDatas));
                }
            }
        }

        public override void Apply()
        {
            List<KeyAssignData> kads = new List<KeyAssignData>();
            foreach (var i in kadatas.Keys)
            {
                kads.Add(new KeyAssignData()
                {
                    LinkedKeys = i,
                    InvokeMethodDatas = kadatas[i].ToArray()
                });
            }
            Core.Config.KeyAssign.KeyAssignData = kads.ToArray();
        }

        private void tgKeyInput_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                case Keys.Down:
                case Keys.Left:
                case Keys.Right:
                    e.IsInputKey = true;
                    break;
            }
        }

        Keys _target = Keys.None;
        Keys target
        {
            get { return _target; }
            set
            {
                if (value == Keys.None) return;
                tgKeyInput.Text = value.ToString();
                var k = GetFormattedKey(value);
                _target = k;
                if (!kadatas.ContainsKey(k))
                    kadatas.Add(k, new List<KeyAssignMethodData>());
                UpdateTargetList();
            }
        }

        private void UpdateTargetList()
        {
            methodList.SuspendLayout();
            methodList.Items.Clear();
            foreach (var i in kadatas[_target])
            {
                methodList.Items.Add(i.Description);
            }
            methodList.ResumeLayout();
        }

        private Keys GetFormattedKey(Keys raw)
        {
            raw &= Keys.KeyCode;
            if (modAlt.Checked)
                raw |= Keys.Alt;
            if (modControl.Checked)
                raw |= Keys.Control;
            if (modShift.Checked)
                raw |= Keys.Shift;
            return raw;
        }

        private void tgKeyInput_KeyDown(object sender, KeyEventArgs e)
        {
            target = e.KeyCode;
        }

        private void modsCheckedChanged(object sender, EventArgs e)
        {
            target = target;
        }

        private void excEnter_Click(object sender, EventArgs e)
        {
            target = Keys.Enter;
        }

        private void excEscape_Click(object sender, EventArgs e)
        {
            target = Keys.Escape;
        }

        private void addCandidate_Click(object sender, EventArgs e)
        {
            kadatas[target].Add(new KeyAssignMethodData(candidates[candidateList.SelectedIndex]));
            UpdateTargetList();
            methodList.SelectedIndex = methodList.Items.Count - 1;
        }

        private void listRemove_Click(object sender, EventArgs e)
        {
            if (methodList.SelectedIndex < 0) return;
            var i = methodList.SelectedIndex;
            kadatas[target].RemoveAt(i);
            UpdateTargetList();
            if (i >= methodList.Items.Count)
                i = methodList.Items.Count - 1;
            methodList.SelectedIndex = i;
        }

        private void listUp_Click(object sender, EventArgs e)
        {
            if (methodList.SelectedIndex < 1) return;
            var i = methodList.SelectedIndex;
            var tmp = kadatas[target][i];
            kadatas[target][i] = kadatas[target][i - 1];
            kadatas[target][i - 1] = tmp;
            UpdateTargetList();
        }

        private void listDown_Click(object sender, EventArgs e)
        {
            if (methodList.SelectedIndex >= methodList.Items.Count - 1) return;
            var i = methodList.SelectedIndex;
            var tmp = kadatas[target][i];
            kadatas[target][i] = kadatas[target][i + 1];
            kadatas[target][i + 1] = tmp;
            UpdateTargetList();
        }

        private void exCapable_Click(object sender, EventArgs e)
        {
            exCandMenus.Show(exCapable, new Point(0, exCapable.Height));
        }
    }
}